#include "Raft/raft.hpp"
#include "common.hpp"
#include <atomic>
#include <iostream>
using namespace std;

#define EVERY_SERVER_PORT 3
int cur_portId = 0;         //为了减轻server端的RPC压力，所以server对PUT,GET,APPEND操作设置了多个RPC端口响应


class Clerk{
public:
    Clerk(vector<vector<int>>& servers);
    void PutAppend(string key, string value, string op);
    string get(string key);                                 //定义的对于kvServer的get请求
    void put(string key, string value);                     //定义的对于kvServer的put请求
    void append(string key, string value);                  //定义的对于kvServer的append请求
    ~Clerk();

private:
    vector<vector<int>> servers;
    int leaderId;   // raft集群leader的id（真正多机器集群中此处改为IP地址）
    int requestId;  // 序列号
    int clientId;   // 客户端ID
};

Clerk::Clerk(vector<vector<int>>& servers){
    this->servers = servers;
    this->clientId = rand() % 1000 + 1;
    this->requestId = 0;
    this->leaderId = rand() % servers.size();
}

Clerk::~Clerk(){
}

void Clerk::PutAppend(string key, string value, string op){
    PutAppendArgs args;
    args.key = key;
    args.value = value;     
    args.op = op;
    args.clientId = clientId;
    args.requestId = requestId;
    int currentLeaderID = leaderId;

    int curPort = (cur_portId++) % EVERY_SERVER_PORT;
    // 轮询
    while (1){
        buttonrpc client;
        client.as_client("127.0.0.1", servers[currentLeaderID][curPort]);
        PutAppendReply reply = client.call<PutAppendReply>("putAppend", args).val();
        if (reply.err == OK){
            return;
        } else if (reply.err == ErrWrongLeader){
            leaderId = (leaderId + 1) % servers.size();
            continue;
        }
    }       
}

string Clerk::get(string key){
    GetArgs args;
    args.key = key;
    args.clientId = clientId;
    args.requestId = requestId++;
    int currentLeaderID = leaderId;

    int curPort = (cur_portId++) % EVERY_SERVER_PORT;
    // 轮询
    while (1){
        buttonrpc client;
        client.as_client("127.0.0.1", servers[currentLeaderID][curPort]);
        GetReply reply = client.call<GetReply>("get", args).val();
        if (reply.err == ErrNoKey){
            return "";
        } else if (reply.err == OK){
            return reply.value;
        } else{
            leaderId = (leaderId + 1) % servers.size();
            continue;
        }
    }
}

void Clerk::put(string key, string value){
    PutAppend(key, value, "put");
}

void Clerk::append(string key, string value){
    PutAppend(key, value, "append");
}


vector<vector<int>> getServerPort(int num){
    vector<vector<int>> kvServerPort(num);
    for(int i = 0; i < num; i++){
        for(int j = 0; j < 3; j++){
            kvServerPort[i].push_back(COMMOM_PORT + i + (j + 2) * num);
        }
    }
    return kvServerPort;
}
int main() {
    srand((unsigned)time(NULL));
    vector<vector<int>> port = getServerPort(5);
    Clerk clerk(port);
    Clerk clerk2(port);
    Clerk clerk3(port);
    Clerk clerk4(port);
    Clerk clerk5(port);

    //-------------------------------------test-------------------------------------
    int times = 30;
    while(times-- > 0){
        clerk.put("abc", "123");
        cout << clerk.get("abc") << endl;
        clerk2.put("abc", "456");
        clerk3.append("abc", "789");
        cout << clerk.get("abc") << endl;
        clerk4.put("bcd", "111");
        cout << clerk.get("bcd") << endl;
        clerk5.append("bcd", "222");
        cout << clerk3.get("bcd") << endl;
        cout << clerk3.get("abcd") << endl;
        clerk5.append("bcd", "222");
        clerk4.append("bcd", "222");
        cout << clerk2.get("bcd") << endl;
        clerk3.append("bcd", "222");
        clerk2.append("bcd", "232");
        cout << clerk4.get("bcd") << endl;
        clerk.append("bcd", "222");
        clerk4.put("bcd", "111");
        cout << clerk3.get("bcd") << endl;
        usleep(10000);
    }
    return 0;
}